package org.dlsu.mt.parser;

import java.util.StringTokenizer;
import java.util.Vector;

import org.dlsu.mt.parser.generator.Rule;

/**
 * The Node class represents a non-leaf node inside the parse tree.
 * A node contains its derivation rule, the left-hand side of the rule as its label,
 * and all its direct descendants. Because of the node having keep track of its direct descendants,
 * which are either a Node (non-leaf) or a Word (leaf), then it indirectly represents the node
 * and its subtree inside the parse tree and the root Node will represent the entire parse tree.
 * The Symbol interface's interpret() method has been implemented to build its F-Structure from
 * its subtree.
 * The '/' symbol is used to represent the up arrow, '\' for the down arrow, '=' for assignment
 * and any attribute name after '\' or '/' symbol. All symbols in the semantics are separated by
 * spaces.
 * Example:
 *		/ multiplicand = \
 */

public class Node implements Symbol{


	/**
	 * The rule which is associated with the node. This is the rule
	 * which the node represents.
	 */
	Rule rule;

	/**
	 * The label of the node,
 	 */

	String label;

	/**
	 * A vector of Symbols ( Nodes or Words ) that represent the
	 * children of the node. This esentially corresponds to
	 * right hand side of the rule.
 	 */

	Vector childList;


	/**
	 * Constructs a node that has an associated rule which it represents
	 * in reducing from its children to itself.
	 *
	 * @param label the name or label for the node
	 * @param rule the Rule associated to the node
	 */

	public Node (String label, Rule rule)
	{
		this.label = label;
		this.rule = rule;
		childList = new Vector();
	}

	/**
	 * Adds a child to the node. This corresponds to the symbols reduced
	 * to this node. The children are ordered according to the order of
	 * addition to the node.
	 *
	 * @param symbol the symbol ( node or word ) to be added as a child
	 */

	public void addChild(Symbol symbol)
	{
		childList.addElement(symbol);
	}

	/**
	 * Returns the a clone or a copy of the node. All the objects
	 * in the used in the node are cloned and not merely referenced.
	 *
	 * @return the clone of the object
	 */
	public Object clone()
	{
		Node node = new Node (this.label, this.rule);
		Symbol s;

		if(this.childList.size()>0)
			for ( int i=0; i<this.childList.size(); i++)
			{
				//System.out.println("Node: Cloning Element "+i+" of "+this);
				s = (Symbol) this.childList.elementAt(i);
				node.childList.addElement(s.clone());
			}
		return node;
	}


	/**
	 * Returns the XML representation of the Node. This method
	 * recursively calls the displayXML() method of its children.
	 * This method will also be used recursively by other
	 * displayXML() methods.
	 *
	 * <Node rule_string="<the production rule used>">
	 *		<child 1>
	 *		<child 2>
	 *		...
	 *		<child n>
	 * </Node>
	 *
	 * @return the string showing the XML representation
	 */
	public String displayXML()
	{
		String s = "<NODE rule_string=\""+rule.toStringNoDot()+"\">";
		for ( int i=0; i<childList.size(); i++)
			s = s+(((Symbol)childList.elementAt(i)).displayXML());
		s = s+ "</NODE>";
		return s;
	}

	/**
	 * Returns the interpretation of the Node object which can be overwritten
	 * to have a different output. But the current implementation is it returns
	 * generated FStructure from its children. This implementation does not exhaust
	 * all possible semantic structures that can be formed when a Word may have
	 * multiple semantic structures.
	 *
	 * @return The combined FStructure of the Node
	 */
	public Object interpret() throws Exception{
		int i;
		String featureString, sTemp;
		StringTokenizer st;
		FStructure fDest, fSource;
		FStructureInterface fTemp, fTemp2, fTemp3, fTempNew;
//		try {
			fDest = new FStructure("root");

			for(i=0;i<rule.getFeatureSize();i++) {
				featureString = (String) rule.getFeature(i);
				if (!featureString.equalsIgnoreCase("")) {
					st = new StringTokenizer(featureString," ");
					fSource = (FStructure) ((Symbol) childList.elementAt(i)).interpret();

					if (fSource == null)
						continue;

					sTemp = st.nextToken();
					fTemp = null;
					fTemp3 = null;
					fTempNew = null;
					if (sTemp.equalsIgnoreCase("/")) {
						while( !(sTemp = st.nextToken()).equalsIgnoreCase("=") )
							if (fTemp == null) {
								fTemp = new FStructure(sTemp);
								fTemp3 = fTemp;
							}
							else {
								fTempNew= new FStructure(sTemp);
								((FStructure) fTemp3).addEntry(fTempNew);
								fTemp3 = fTempNew;
							}
						if (fTemp == null)
							fTemp = fDest;
						sTemp = st.nextToken();
						fTemp2 = null;
						if (sTemp.equalsIgnoreCase("\\")) {
							while(st.hasMoreTokens()) {
								sTemp = st.nextToken();
								if (fTemp2 == null)
									fTemp2 = fSource.getEntry(sTemp);
								else
									fTemp2 = ((FStructure) fTemp2).getEntry(sTemp);
							}
							if (fTemp2 == null)
								fTemp2 = (FStructureInterface) fSource.clone();
						} else
							throw new RuntimeException("Unsupported LFG Structure: < on the right hand side");
					}
					else
						throw new RuntimeException("Unsupported LFG Structure: "+sTemp+" on the left hand side");

					if (fTempNew == null) {
						if (((FStructure) fTemp).merge(fTemp2) == false) 
							{
								System.out.println("merge failed"); 
								return null;	
							}
					}
					else {
						if (((FStructure) fTempNew).merge(fTemp2) == false) 
						{ 
							System.out.println("merge fail");
							return null;	
						}
					}

					if (fDest != fTemp)
						if ( fDest.addEntry(fTemp) == false) {
							return null;
						}
				}
			}

//			if (fDest == null)
//				System.out.println("HI!");
			if(fDest!=null)
				fDest.clearEmpty();
			return fDest;
//		} catch (Exception e) {
//			throw new RuntimeException(e.getMessage() + " occured in rule " + rule.toString());
//		}
	}


}